Skip to content

Commit fe1bb1f

Browse files
stephenmcgruermoz-wptsync-bot
authored andcommitted
Bug 1627357 [wpt PR 22699] - Implement assert_implements and assert_implements_optional, a=testonly
Automatic update from web-platform-tests Implement assert_implements and assert_implements_optional (#22699) See web-platform-tests/rfcs#48 and web-platform-tests/wpt#21971. Note that this PR only implements the new methods; it does not port any tests to use it or remove `assert_precondition` - that will be done in follow-up PRs. -- wpt-commits: d97d993e1c3977da9fe88ca2c867cd4466582eee wpt-pr: 22699
1 parent cc0ec80 commit fe1bb1f

File tree

8 files changed

+181
-39
lines changed

8 files changed

+181
-39
lines changed

testing/web-platform/tests/docs/writing-tests/testharness-api.md

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -313,40 +313,44 @@ NOTE: All asserts must be located in a `test()` or a step of an
313313
these places won't be detected correctly by the harness and may cause
314314
unexpected exceptions that will lead to an error in the harness.
315315
316-
## Preconditions ##
316+
## Optional Features ##
317317
318-
When a test would be invalid unless certain conditions are met, but yet
319-
doesn't explicitly depend on those preconditions, `assert_precondition` can be
320-
used. For example:
318+
If a test depends on a specification or specification feature that is OPTIONAL
319+
(in the [RFC 2119 sense](https://tools.ietf.org/html/rfc2119)),
320+
`assert_implements_optional` can be used to indicate that failing the test does
321+
not mean violating a web standard. For example:
321322
322323
```js
323324
async_test((t) => {
324325
const video = document.createElement("video");
325-
assert_precondition(video.canPlayType("video/webm"));
326+
assert_implements_optional(video.canPlayType("video/webm"));
326327
video.src = "multitrack.webm";
327328
// test something specific to multiple audio tracks in a WebM container
328329
t.done();
329330
}, "WebM with multiple audio tracks");
330331
```
331332
332-
A failing `assert_precondition` call is reported as a status of
333-
`PRECONDITION_FAILED` for the subtest.
333+
A failing `assert_implements_optional` call is reported as a status of
334+
`PRECONDITION_FAILED` for the subtest. This unusual status code is a legacy
335+
leftover from the deprecated `assert_precondition`; see the [RFC that renamed
336+
it](https://github.com/web-platform-tests/rfcs/pull/48).
334337
335-
`assert_precondition` can also be used during test setup. For example:
338+
`assert_implements_optional` can also be used during test setup. For example:
336339
337340
```js
338341
setup(() => {
339-
assert_precondition("onfoo" in document.body, "'foo' event supported");
342+
assert_implements_optional("optionalfeature" in document.body,
343+
"'optionalfeature' event supported");
340344
});
341-
async_test(() => { /* test #1 waiting for "foo" event */ });
342-
async_test(() => { /* test #2 waiting for "foo" event */ });
345+
async_test(() => { /* test #1 waiting for "optionalfeature" event */ });
346+
async_test(() => { /* test #2 waiting for "optionalfeature" event */ });
343347
```
344348
345-
A failing `assert_precondition` during setup is reported as a status of
349+
A failing `assert_implements_optional` during setup is reported as a status of
346350
`PRECONDITION_FAILED` for the test, and the subtests will not run.
347351
348-
See also the `.optional` [file name convention](file-names.md), which is
349-
appropriate when the precondition is explicitly optional behavior.
352+
See also the `.optional` [file name convention](file-names.md), which may be
353+
preferable if the entire test is optional.
350354
351355
## Cleanup ##
352356
@@ -772,10 +776,6 @@ workers and want to ensure they run in series:
772776
773777
## List of Assertions ##
774778
775-
### `assert_precondition(condition, description)`
776-
asserts that `condition` is truthy.
777-
See [preconditions](#preconditions) for usage.
778-
779779
### `assert_true(actual, description)`
780780
asserts that `actual` is strictly true
781781
@@ -885,6 +885,13 @@ that the exception should have as its .constructor. For example,
885885

886886
`func` - a function that should throw
887887

888+
### `assert_implements(condition, description)`
889+
asserts that a feature is supported, by checking if `condition` is truthy.
890+
891+
### `assert_implements_optional(condition, description)`
892+
asserts that an optional feature is supported, by checking if `condition` is truthy.
893+
See [Optional Features](#optional-features) for usage.
894+
888895
### `assert_unreached(description)`
889896
asserts if called. Used to ensure that some codepath is *not* taken e.g.
890897
an event does not fire.
@@ -897,6 +904,9 @@ asserts that one `assert_func(actual, expected_array_N, extra_arg1, ..., extra_a
897904
allows multiple behaviours. Test authors should not use this method simply to hide
898905
UA bugs.
899906

907+
### **DEPRECATED** `assert_precondition(condition, description)`
908+
Use `assert_implements` or `assert_implements_optional` instead.
909+
900910
## Utility functions ##
901911

902912
### **DEPRECATED** `on_event(object, event, callback)`

testing/web-platform/tests/fetch/metadata/portal.https.sub.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
function create_test(host, expectations) {
1414
async_test(t => {
15-
assert_precondition("HTMLPortalElement" in window, "Portals are not supported.");
15+
assert_implements("HTMLPortalElement" in window, "Portals are not supported.");
1616

1717
let p = document.createElement('portal');
1818
p.addEventListener('message', t.step_func(e => {

testing/web-platform/tests/html/semantics/embedded-content/the-video-element/resize-during-playback.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
for (const format of ['mp4', 'webm']) {
1313
promise_test(async (t) => {
1414
const video = document.createElement('video');
15-
assert_precondition(video.canPlayType(`video/${format}`), `${format} supported`);
15+
assert_implements_optional(video.canPlayType(`video/${format}`), `${format} supported`);
1616

1717
// Load the video and wait for initial resize event.
1818
video.src = `/media/400x300-red-resize-200x150-green.${format}`;
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE HTML>
2+
<html lang="en">
3+
<meta charset="utf-8">
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/resources/test/tests/unit/helpers.js"></script>
7+
<title>assert_implements unittests</title>
8+
<script>
9+
'use strict';
10+
11+
test(() => {
12+
// All values in JS that are not falsy are truthy, so we just check some
13+
// common cases here.
14+
assert_implements(true, 'true is a truthy value');
15+
assert_implements(5, 'positive integeter is a truthy value');
16+
assert_implements(-5, 'negative integeter is a truthy value');
17+
assert_implements('foo', 'non-empty string is a truthy value');
18+
}, 'truthy values');
19+
20+
test_failure(() => {
21+
assert_implements(false);
22+
}, 'false is a falsy value');
23+
24+
test_failure(() => {
25+
assert_implements(0);
26+
}, '0 is a falsy value');
27+
28+
test_failure(() => {
29+
assert_implements('');
30+
}, 'empty string is a falsy value');
31+
32+
test_failure(() => {
33+
assert_implements(null);
34+
}, 'null is a falsy value');
35+
36+
test_failure(() => {
37+
assert_implements(undefined);
38+
}, 'undefined is a falsy value');
39+
40+
test_failure(() => {
41+
assert_implements(NaN);
42+
}, 'NaN is a falsy value');
43+
</script>
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
<!DOCTYPE HTML>
2+
<html lang="en">
3+
<meta charset="utf-8">
4+
<script src="/resources/testharness.js"></script>
5+
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/resources/test/tests/unit/helpers.js"></script>
7+
<title>assert_implements_optional unittests</title>
8+
<script>
9+
'use strict';
10+
11+
test(() => {
12+
// All values in JS that are not falsy are truthy, so we just check some
13+
// common cases here.
14+
assert_implements_optional(true, 'true is a truthy value');
15+
assert_implements_optional(5, 'positive integeter is a truthy value');
16+
assert_implements_optional(-5, 'negative integeter is a truthy value');
17+
assert_implements_optional('foo', 'non-empty string is a truthy value');
18+
}, 'truthy values');
19+
20+
test_failure(() => {
21+
assert_implements_optional(false);
22+
}, 'false is a falsy value');
23+
24+
test_failure(() => {
25+
assert_implements_optional(0);
26+
}, '0 is a falsy value');
27+
28+
test_failure(() => {
29+
assert_implements_optional('');
30+
}, 'empty string is a falsy value');
31+
32+
test_failure(() => {
33+
assert_implements_optional(null);
34+
}, 'null is a falsy value');
35+
36+
test_failure(() => {
37+
assert_implements_optional(undefined);
38+
}, 'undefined is a falsy value');
39+
40+
test_failure(() => {
41+
assert_implements_optional(NaN);
42+
}, 'NaN is a falsy value');
43+
</script>

testing/web-platform/tests/resources/test/tests/unit/assert_object_equals.html

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3,29 +3,11 @@
33
<meta charset="utf-8">
44
<script src="/resources/testharness.js"></script>
55
<script src="/resources/testharnessreport.js"></script>
6+
<script src="/resources/test/tests/unit/helpers.js"></script>
67
<title>Assertion functions</title>
78
<script>
89
'use strict';
910

10-
// The `assert_throws_*` functions cannot be used for this
11-
// purpose because they fail in response to AssertionError exceptions, even
12-
// when this is expressed as the expected error.
13-
function test_failure(fn, name) {
14-
test(function() {
15-
try {
16-
fn();
17-
} catch (err) {
18-
if (err instanceof AssertionError) {
19-
return;
20-
}
21-
throw new AssertionError('Expected an AssertionError, but');
22-
}
23-
throw new AssertionError(
24-
'Expected an AssertionError, but no error was thrown'
25-
);
26-
}, name);
27-
}
28-
2911
test(function() {
3012
assert_object_equals({}, {});
3113
}, 'empty objects');
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Helper for testing assertion failure cases for a testharness.js API
2+
//
3+
// The `assert_throws_*` functions cannot be used for this purpose because they
4+
// always fail in response to AssertionError exceptions, even when this is
5+
// expressed as the expected error.
6+
function test_failure(fn, name) {
7+
test(function() {
8+
try {
9+
fn();
10+
} catch (err) {
11+
if (err instanceof AssertionError) {
12+
return;
13+
}
14+
throw new AssertionError('Expected an AssertionError, but');
15+
}
16+
throw new AssertionError(
17+
'Expected an AssertionError, but no error was thrown'
18+
);
19+
}, name);
20+
}
21+

testing/web-platform/tests/resources/testharness.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1848,6 +1848,49 @@ policies and contribution forms [3].
18481848
}
18491849
expose(assert_any, "assert_any");
18501850

1851+
/**
1852+
* Assert that a feature is implemented, based on a 'truthy' condition.
1853+
*
1854+
* This function should be used to early-exit from tests in which there is
1855+
* no point continuing without support for a non-optional spec or spec
1856+
* feature. For example:
1857+
*
1858+
* assert_implements(window.Foo, 'Foo is not supported');
1859+
*
1860+
* @param {object} condition The truthy value to test
1861+
* @param {string} description Error description for the case that the condition is not truthy.
1862+
*/
1863+
function assert_implements(condition, description) {
1864+
assert(!!condition, "assert_implements", description);
1865+
}
1866+
expose(assert_implements, "assert_implements")
1867+
1868+
/**
1869+
* Assert that an optional feature is implemented, based on a 'truthy' condition.
1870+
*
1871+
* This function should be used to early-exit from tests in which there is
1872+
* no point continuing without support for an explicitly optional spec or
1873+
* spec feature. For example:
1874+
*
1875+
* assert_implements_optional(video.canPlayType("video/webm"),
1876+
* "webm video playback not supported");
1877+
*
1878+
* @param {object} condition The truthy value to test
1879+
* @param {string} description Error description for the case that the condition is not truthy.
1880+
*/
1881+
function assert_implements_optional(condition, description) {
1882+
if (!condition) {
1883+
// Due to the difficulty of changing logging statuses, we re-use
1884+
// the PRECONDITION_FAILED status for assert_implements_optional.
1885+
// See the RFC: https://github.com/web-platform-tests/rfcs/pull/48
1886+
//
1887+
// TODO(smcgruer): Once assert_precondition is removed, rename the
1888+
// exception and move this comment to where PRECONDITION_FAILED is used.
1889+
throw new PreconditionFailedError(description);
1890+
}
1891+
}
1892+
expose(assert_implements_optional, "assert_implements_optional")
1893+
18511894
function assert_precondition(precondition, description) {
18521895
if (!precondition) {
18531896
throw new PreconditionFailedError(description);

0 commit comments

Comments
 (0)